﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Media;
using GenericQuadTree;

namespace QuadTreeDemo
{
    public partial class MainPage
    {
        private readonly List<Taxi> _taxis = new List<Taxi>();
        private QuadNode<TaxiContainer> _lastNode;
        private QuadNode<TaxiContainer> _currentNode;

        private const int TaxiCount = 2000;
        private readonly QuadTree<TaxiContainer> _tree;

        private readonly SolidColorBrush _strokeBrush = new SolidColorBrush(Color.FromArgb(0xff, 0x00, 0x00, 0x00));
        private readonly SolidColorBrush _nonTargetFill = new SolidColorBrush(Color.FromArgb(0x66, 0x00, 0x00, 0x00));
        readonly List<Rectangle> _targetGrid = new List<Rectangle>();

        public MainPage()
        {
            InitializeComponent();
            _tree = new QuadTree<TaxiContainer>(TaxiCanvas.Width - 10, TaxiCanvas.Height - 10, 40, 40, new Point(0, 0));
            CountNodes();
            GenerateTaxis();
        }

        private void CountNodes()
        {

        }

        private void GenerateTaxis()
        {
            var rnd = new Random();
            for (var i = 0; i < TaxiCount; i++)
            {
                var location = new Point(rnd.Next(10, (int)TaxiCanvas.Width - 10), rnd.Next(10, (int)TaxiCanvas.Height - 10));
                var taxiContainer = new TaxiContainer(location);

                _taxis.Add(taxiContainer.Taxi);
                TaxiCanvas.Children.Add(taxiContainer.Taxi);
                _tree.AddItem(taxiContainer);
            }

            infoBox.TaxiCount = TaxiCount;

        }

        private void Element_MouseMove(object sender, MouseEventArgs e)
        {
            var location = new Point(e.GetPosition((UIElement) sender).X, e.GetPosition((UIElement) sender).Y);


            _currentNode = _tree.GetNodeAtLocation(location);


            if (_lastNode != _currentNode)
            {
                if (_lastNode != null)
                {
                    foreach (var t in _lastNode.Items)
                        t.Taxi.Deactivate();              
                }

                if (_currentNode != null)
                {
                    foreach (var t in _currentNode.Items)
                        t.Taxi.Activate();
                
                    UpdateTargetGrid(_currentNode, location);

                }
                else
                {
                    if (_lastNode != null)
                        foreach (var t in _lastNode.Items)
                            t.Taxi.Deactivate();                 

                    RemoveTargetGrid();
                    NodeRect.Visibility = Visibility.Collapsed;
                }
            }
            _lastNode = _currentNode;

            UpdateInfoBox();
        }

        private void UpdateTargetGrid(QuadNode<TaxiContainer> node, Point location)
        {
            RemoveTargetGrid();

            if (node == null) return;

            if (node.ParentNode == null)
            {
                var rect = new Rectangle
                               {
                                   Stroke = _strokeBrush,
                                   IsHitTestVisible = false,
                                   Width = node.Width,
                                   Height = node.Height
                               };
                _targetGrid.Add(rect);

                rect.SetValue(Canvas.LeftProperty, node.Location.X);
                rect.SetValue(Canvas.TopProperty, node.Location.Y);

                TaxiCanvas.Children.Add(rect);

                return;
            }

            var currentNode = node.ParentNode;

            //while (currentNode.NodeType != NodeType.Full)
            while(currentNode != null)
            {
                foreach (var child in currentNode.Children)
                {
                    var rect = new Rectangle
                                {
                                    Stroke = _strokeBrush,
                                    IsHitTestVisible = false,
                                    Width = child.Width,
                                    Height = child.Height
                                };

                    rect.SetValue(Canvas.LeftProperty, child.Location.X);
                    rect.SetValue(Canvas.TopProperty, child.Location.Y);

                    //Since neighbor nodes share a common edge along the location, subtracting a 
                    //miniscule amount to avoid errors in determining node.  This is only for 
                    //display of the rectangles and should not be considered when constructing 
                    //quad tree.
                    if (!child.ContainsPoint(new Point(location.X - 0.0000001, location.Y - 0.0000001)))
                        rect.Fill = _nonTargetFill;

                    _targetGrid.Add(rect);
                }

                currentNode = currentNode.ParentNode;
            }

            DrawTargetGrid();

            
        }

        private void RemoveTargetGrid()
        {
            foreach (var t in _targetGrid)
                TaxiCanvas.Children.Remove(t);

            _targetGrid.Clear();
        }

        private void DrawTargetGrid()
        {
            if(checkBox1.IsChecked == true)
                foreach (var t in _targetGrid)
                    TaxiCanvas.Children.Add(t);
                
        }

        private void UpdateInfoBox()
        {
            infoBox.NodesQueried = 0;
            infoBox.SelectedTaxis = 0;
            infoBox.NodeDepth = 0;

            if (_currentNode != null)
            {
                infoBox.SelectedTaxis = _currentNode.Items.Count;
                infoBox.NodeDepth = _currentNode.Depth;
                infoBox.TotalNodes = (int)Math.Pow(_currentNode.Depth, 4) + 1;
                var node = _currentNode;
                int nodeQuery = 0;
                while (node != null)
                {
                    nodeQuery += (int)node.NodeType;
                    node = node.ParentNode;
                }

                //Add one for the parent node
                infoBox.NodesQueried = nodeQuery;
            }

        }

        private void checkBox1_Checked(object sender, RoutedEventArgs e)
        {
            if (checkBox1.IsChecked == false)
            {
                RemoveTargetGrid();
                return;
            }

            DrawTargetGrid();
        }
    }
}